package util

import (
	"fmt"
)

type tagType struct{}

var tag = tagType{}

type Set[valueType comparable] struct {
	m map[valueType]tagType
}

// 可字符串化
var _ fmt.Stringer = &Set[string]{}

// FIXME 以下需 Go 1.20
// var _ fmt.Stringer = &Set[interface{}]{}

// String 返回集合的字符串表示
func (s *Set[valueType]) String() (str string) {
	str = "{"
	for k := range s.m {
		str += fmt.Sprintf("%v, ", k)
	}
	str += "}"
	return
}

// NewSet 新建一个集合
func NewSet[valueType comparable]() *Set[valueType] {
	return &Set[valueType]{m: make(map[valueType]tagType)}
}

// DeepCopy 深拷贝
func (s *Set[valueType]) DeepCopy() *Set[valueType] {
	newSet := NewSet[valueType]()
	newSet.Merge(s)
	return newSet
}

// Add 向集合中加入值
func (s *Set[valueType]) Add(value valueType) {
	s.m[value] = tag
}

// Check 检查集合中是否存在某个值
func (s *Set[valueType]) Check(value valueType) (exists bool) {
	_, exists = s.m[value]
	return
}

// CheckAndAdd 向集合中加入值，返回加入前是否存在相同值
func (s *Set[valueType]) CheckAndAdd(value valueType) (exists bool) {
	_, exists = s.m[value]
	s.Add(value)
	return
}

// Merge 合并两个集合
func (s *Set[valueType]) Merge(set *Set[valueType]) {
	for k := range set.m {
		s.Add(k)
	}
}

// CheckAndMerge 合并两个集合，返回两个集合间是否存在相同值
func (s *Set[valueType]) CheckAndMerge(set *Set[valueType]) (exists bool) {
	var nowExists bool
	for k := range set.m {
		nowExists = s.CheckAndAdd(k)
		exists = exists || nowExists
	}
	return
}

// GetAll 获取集合中的所有值，返回值的顺序不确定
func (s *Set[valueType]) GetAll() (list []valueType) {
	for k := range s.m {
		list = append(list, k)
	}
	return
}

// IsEmpty 判断是否为空
func (s *Set[valueType]) IsEmpty() (empty bool) {
	return len(s.m) == 0
}

// Len 获取集合的大小
func (s *Set[valueType]) Len() (length int) {
	return len(s.m)
}
